import type { IFileInfo } from '@/components/base-upload/types.ts'
import { isEffectiveURL, refreshURL } from '@/components/base-upload/util.ts'
import type { IPreviewCommonOptions, ISrc, TSrc } from '@shared/base/open/preview-types.ts'
import { openPreview } from '@shared/base/open'

/**
 * 获取文件后缀
 *
 * @param {string} filename - 文件名
 * @returns {string} 文件后缀
 *
 * @example
 * getFileExtension('example.txt'); // 返回: "txt"
 *
 * @example
 * getFileExtension('my.photo.jpeg'); // 返回: "jpeg"
 *
 * @example
 * getFileExtension('archive'); // 返回: ""
 */
export function getFileExtension(filename: string): string {
  // 检查文件名是否为有效字符串
  if (typeof filename !== 'string') {
    return ''
  }

  // 获取最后一个点的位置
  const lastDotIndex = filename.lastIndexOf('.')

  // 如果没有点或点在第一个字符位置，返回空字符串
  if (lastDotIndex === -1 || lastDotIndex === 0) {
    return ''
  }

  // 返回文件后缀
  return filename.substring(lastDotIndex + 1)
}

/**
 * 格式化文件大小
 * @param size 文件大小（以字节为单位）
 * @param digits
 * @returns 格式化后的文件大小字符串
 *
 * @example
 * formatFileSize(500); // "500 B"
 * formatFileSize(1500); // "1.46 KB"
 * formatFileSize(1048576); // "1.00 MB"
 * formatFileSize(1073741824); // "1.00 GB"
 */
export function formatFileSize(size: number, digits = 2): string {
  if (size < 1024) {
    return `${size}B`
  } else if (size < 1024 * 1024) {
    return `${(size / 1024).toFixed(digits)}KB`
  } else if (size < 1024 * 1024 * 1024) {
    return `${(size / (1024 * 1024)).toFixed(digits)}MB`
  } else {
    return `${(size / (1024 * 1024 * 1024)).toFixed(digits)}GB`
  }
}

/**
 * 更新文件预览地址
 * @param fileList 文件或文件数组
 * @returns Promise 包含更新后的文件或文件数组
 */
export function refreshPreviewUrl<T extends IFileInfo | IFileInfo[]>(fileList: T): Promise<T> {
  const files = Array.isArray(fileList) ? fileList : [fileList]

  const updateTasks = files.map(async (file) => {
    // 如果文件没有预览地址或预览地址无效
    if (!file.previewUrl || !isEffectiveURL(file)) {
      file.previewUrl = (await refreshURL(file)).previewUrl
    }
    return file
  })

  // 使用类型断言保证返回类型匹配
  return (Array.isArray(fileList) ? Promise.all(updateTasks) : updateTasks[0]) as Promise<T>
}

/**
 * 兼容文件信息，将文件信息转换为可打开预览的格式
 * @param fileInfo
 */
export async function compatOpenPreviewUrl<T extends IFileInfo & ISrc>(fileInfo: T): Promise<T> {
  if (fileInfo?.bucketName) {
    // 如果存在 bucketName 字段值 说明是后端返回的文件信息
    const fileInfoPure = await refreshPreviewUrl(fileInfo)
    return {
      ...(fileInfo || {}),
      ...(fileInfoPure || {}),
      filePath: fileInfoPure?.previewUrl || fileInfo?.previewUrl || fileInfo?.filePath
    } as unknown as Promise<T>
  }
  return {
    ...(fileInfo || {}),
    filePath: (fileInfo?.previewUrl || fileInfo?.filePath) as string
  } as unknown as Promise<T>
}

type TSrcCompat = TSrc & IFileInfo // 兼容

/**
 * 预览
 * @example
 * ```js
 *
const fileInfo = {
  fileName: 'BowlingBallCali_ZH-CN0434558966_UHD.jpg', // 自定义文件名
  filePath: 'fada/test/1848613483432632320_BowlingBallCali_ZH-CN0434558966_UHD.jpg',
  bucketName: 'cf-private',
  fileSize: 3060400,
  previewUrl:
    'http://10.86.120.250:19000/cf-private/fada/test/1848613483432632320_BowlingBallCali_ZH-CN0434558966_UHD.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=O9WUEFSKN2JQ5IAMGPCJ%2F20241022%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20241022T063254Z&X-Amz-Expires=180&X-Amz-SignedHeaders=host&X-Amz-Signature=61f34af1a99bdbbd25fee520f84015628b325c191958477c8f577d398735e717'
}

// 传入多个
openPreviewCompat([fileInfo], {
  isDownload: false // 是否下载
})

// 传入单个
openPreviewCompat(
  fileInfo,
  {
    isDownload: false // 是否下载
  }
)

// 传入单个, 指定必须以图片方式打开
openPreviewCompat({...fileInfo, type: 'image'}, {
  isDownload: false // 是否下载
})

// 传入单个, 指定必须以pdf方式打开 type 类型有 : 'video' | 'image' | 'pdf' | 'excel' | 'docx' | 'text'
openPreviewCompat({...fileInfo, type: 'pdf'}, {
  isDownload: false // 是否下载
})

// 传入单个, 指定名字名字下载
openPreviewCompat({...fileInfo, fileName: '我在测试数据.png', type: 'image'}, {
  isDownload: true // 设置为true
})

 * ```
 */
export function openPreviewCompat(fileInfoList: TSrcCompat[] | TSrcCompat, options?: IPreviewCommonOptions) {
  return openPreview(fileInfoList, {
    beforePreview: compatOpenPreviewUrl as unknown as IPreviewCommonOptions['beforePreview'],
    initialIndex: 0,
    ...(options || {})
  })
}
